home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr46
/
vfwdk.zip
/
VFWSDK.ZIP
/
SAMPLES
/
ICSAMPLE
/
ICSAMPLE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-02-05
|
43KB
|
1,439 lines
/****************************************************************************
*
* icsample.c
*
* ICSAMPLE is a sample installable compressor for Video for Windows.
*
* Copyright (c) 1991-1993 Microsoft Corporation. All Rights Reserved.
*
* You have a royalty-free right to use, modify, reproduce and
* distribute the Sample Files (and/or any modified version) in
* any way you find useful, provided that you agree that
* Microsoft has no warranty obligations or liability for any
* Sample Application Files.
*
***************************************************************************/
#include <windows.h>
#include <mmsystem.h>
#include <compddk.h>
#include "icsample.h"
/*****************************************************************************
*
* Sample video compressor. This code demonstrates how to implement an
* installable compressor.
*
* The alogorithm we use is very simple:
* (1) Keep one out of every 'n' pixels where 'n' is configurable.
* Compression is done on a scan-line basis.
*
* (2) For true-color images (16 or 24 bits) give the option of dropping
* some of the lower bits.
*
****************************************************************************/
typedef BYTE _huge *HPBYTE ;
typedef WORD _huge *HPWORD ;
typedef DWORD _huge *HPDWORD ;
#define MODNAME "ICSAMPLE"
char szDescription[] = "Microsoft Sample Compressor";
char szName[] = "MS-Samp";
#define FOURCC_SAMP mmioFOURCC('S','A','M','P')
#define TWOCC_SAMP aviTWOCC('d', 'c')
#define BI_SAMP mmioFOURCC('S','m','p','1')
#define VERSION_SAMP 0x00010000 // 1.00
extern HANDLE ghModule ;
/*****************************************************************************
*
* DefaultState holds the compression options that will be used if the user
* compresses an image without configuring us at all first. In the case of
* the sample compressor, it is the pixel keep ratio.
*
****************************************************************************/
ICSTATE DefaultState = {FOURCC_SAMP,2,0};
BOOL FAR PASCAL _loadds ConfigureDlgProc(HWND hdlg, short msg, WORD wParam, LONG lParam);
/*****************************************************************************
*
* Various macros that are useful when dealing with bitmaps.
*
****************************************************************************/
#define ALIGNULONG(i) ((i+3)&(~3)) /* ULONG aligned ! */
#define WIDTHBYTES(i) ((unsigned)((i+31)&(~31))/8) /* ULONG aligned ! */
#define DIBWIDTHBYTES(bi) (int)WIDTHBYTES((int)(bi).biWidth * (int)(bi).biBitCount)
/*****************************************************************************
*
* Function for buffering bits
*
****************************************************************************/
typedef struct tagBitBuffer
{
HPWORD lpwBuffer ;
DWORD dwStored ;
WORD wMask ;
WORD wFile ;
} BITBUFFER, FAR *LPBITBUFFER ;
#define MAX_MASK (0x8000L)
void InitBitBuffer( LPBITBUFFER lpbb,void _huge *lpwBuffer )
{
/*
** Same code is valid for both input and output
*/
lpbb->lpwBuffer = lpwBuffer ;
lpbb->dwStored = 0 ;
lpbb->wMask = MAX_MASK ;
lpbb->wFile = 0 ;
}
void OutputBits( LPBITBUFFER lpbb, WORD wBits, WORD wCount )
{
WORD wMask ;
wMask = 1 << (wCount-1) ;
while (wMask)
{
if (wMask&wBits)
lpbb->wFile |= lpbb->wMask ;
lpbb->wMask >>= 1 ;
if ( !lpbb->wMask )
{
*lpbb->lpwBuffer++ = lpbb->wFile ;
lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
lpbb->wFile = 0 ;
lpbb->wMask = MAX_MASK ;
}
wMask >>= 1 ;
}
}
void OutputBitsFlush( LPBITBUFFER lpbb )
{
if (lpbb->wMask != MAX_MASK)
{
*lpbb->lpwBuffer++ = lpbb->wFile ;
lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
}
}
WORD InputBits( LPBITBUFFER lpbb, WORD wCount )
{
WORD wMask ;
WORD wRet ;
wMask = 1 << (wCount-1) ;
wRet = 0 ;
while (wMask)
{
if (lpbb->wMask == MAX_MASK)
{
lpbb->wFile = *lpbb->lpwBuffer++ ;
lpbb->dwStored += sizeof(*lpbb->lpwBuffer) ;
}
if (lpbb->wFile&lpbb->wMask)
wRet |= wMask ;
wMask >>= 1 ;
lpbb->wMask >>= 1 ;
if (!lpbb->wMask)
lpbb->wMask = MAX_MASK ;
}
return wRet ;
}
/*****************************************************************************
*
* MyCompress
*
* This routine handles the acutal compression of the bitmap. Note:
*
* 1) The use of _huge pointers as the bitmaps are likely to exceed 64k.
*
* 2) We must set the biCompression field of the output header.
*
* 3) We must set the biSizeImage field of the output header.
*
* 4) Uncompressed bitmap scan lines are padded out to the next DWORD
* boundry.
*
****************************************************************************/
void NEAR PASCAL MyCompress8(
INSTINFO * pinst,
LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
LPBITMAPINFOHEADER lpbiOutput,HPBYTE hpOutput)
{
WORD wRealLineSize ;
WORD wLinePad ;
WORD wWidth = (WORD)lpbiInput->biWidth ;
WORD wHeight = (WORD)lpbiInput->biHeight ;
WORD x,y ;
WORD wPixRatio = pinst->CurrentState.wPixelKeepRatio ;
DPF("Compress8()");
lpbiOutput->biBitCount = 8;
lpbiOutput->biCompression = BI_SAMP;
lpbiOutput->biSizeImage = sizeof(WORD)+((wWidth+wPixRatio-1)/wPixRatio)*(DWORD)wHeight;
wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth) ;
wLinePad = wWidth-wRealLineSize ;
*(ICSTATE _huge *)hpOutput = pinst->CurrentState ;
hpOutput += sizeof(ICSTATE) ;
for (y=0; y<wHeight; y++ )
{
for (x=0; x<wWidth; x += wPixRatio)
{
*hpOutput++ = *hpInput ;
hpInput += min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
}
hpInput += wLinePad ;
}
}
/*****************************************************************************
*
* 16/24 bit compression. Same thing; we just deal with a 2 or 3 bytes per pixel
* instead of a byte.
*
* Note that 8-bit pixel values are indices into a palette; 16-bit and
* about are actual color values. In particular, 16-bit values are
* stored as:
*
* +-+-----+-----+-----+
* | | R | G | B |
* +-+-----+-----+-----+
* 1 1 1
* 5 4 0 9 5 4 0
*
* Bit 15 is unused; each of red, green, and blue get 5 bits of color data
* (0-31).
*
* For 24 bit images, each pixel is three bytes long. The bytes hold
* the blue, green, and red values respectively (NOTE THE ORDER IS
* OPPOSITE OF RGB!)
*
****************************************************************************/
void NEAR PASCAL MyCompress16(
INSTINFO * pinst,
LPBITMAPINFOHEADER lpbiInput, HPWORD hpInput,
LPBITMAPINFOHEADER lpbiOutput,HPWORD hpOutput)
{
WORD wRealLineSize ;
WORD wLinePad ;
WORD wWidth = (WORD)lpbiInput->biWidth ;
WORD wHeight = (WORD)lpbiInput->biHeight ;
WORD x,y ;
WORD wPixRatio = pinst->CurrentState.wPixelKeepRatio ;
WORD wDropBits = pinst->CurrentState.wColorBitsToDrop ;
WORD wKeepBits = 5 - wDropBits ;
WORD r,g,b ;
BITBUFFER bb ;
DPF("Compress16()") ;
lpbiOutput->biBitCount = 16;
lpbiOutput->biCompression = BI_SAMP;
lpbiOutput->biSizeImage = sizeof(WORD)+2*((wWidth+wPixRatio-1)/wPixRatio)*(DWORD)wHeight;
wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*2) ;
wLinePad = wWidth*2-wRealLineSize ;
*(ICSTATE _huge *)hpOutput = pinst->CurrentState ;
hpOutput += sizeof(ICSTATE) ;
InitBitBuffer( &bb,hpOutput ) ;
for (y=0; y<wHeight; y++ )
{
for (x=0; x<wWidth; x += wPixRatio)
{
r = ((*hpInput>>10)&0x1F)>>wDropBits ;
g = ((*hpInput>>5)&0x1F)>>wDropBits ;
b = (*hpInput&0x1F)>>wDropBits ;
hpInput += min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
OutputBits( &bb, r, wKeepBits ) ;
OutputBits( &bb, g, wKeepBits ) ;
OutputBits( &bb, b, wKeepBits ) ;
}
hpInput += wLinePad ;
}
OutputBitsFlush(&bb) ;
lpbiOutput->biSizeImage = sizeof(ICSTATE) + bb.dwStored ;
}
void NEAR PASCAL MyCompress24(
INSTINFO * pinst,
LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
LPBITMAPINFOHEADER lpbiOutput,HPBYTE hpOutput)
{
WORD wRealLineSize ;
WORD wLinePad ;
WORD wWidth = (WORD)lpbiInput->biWidth ;
WORD wHeight = (WORD)lpbiInput->biHeight ;
WORD x,y ;
WORD wPixRatio = pinst->CurrentState.wPixelKeepRatio ;
WORD wDropBits = pinst->CurrentState.wColorBitsToDrop ;
WORD wKeepBits = 8 - wDropBits ;
WORD r,g,b ;
BITBUFFER bb ;
DPF("Compress24()") ;
lpbiOutput->biBitCount = 24 ;
lpbiOutput->biCompression = BI_SAMP;
wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*3) ;
wLinePad = wWidth*3-wRealLineSize ;
*(ICSTATE _huge *)hpOutput = pinst->CurrentState ;
hpOutput += sizeof(ICSTATE) ;
InitBitBuffer( &bb,hpOutput ) ;
for (y=0; y<wHeight; y++ )
{
for (x=0; x<wWidth; x += wPixRatio)
{
b = (hpInput[0])>>wDropBits ;
g = (hpInput[1])>>wDropBits ;
r = (hpInput[2])>>wDropBits ;
hpInput += 3 * min(wPixRatio,(WORD)lpbiInput->biWidth-x) ;
OutputBits( &bb, r, wKeepBits ) ;
OutputBits( &bb, g, wKeepBits ) ;
OutputBits( &bb, b, wKeepBits ) ;
}
hpInput += wLinePad ;
}
OutputBitsFlush(&bb) ;
lpbiOutput->biSizeImage = sizeof(ICSTATE) + bb.dwStored ;
}
/*****************************************************************************
*
* MyDecompress
*
* This function is the inverse of MyCompress and follows the same caveats.
*
* We shouldn't depend on the state to accurately tell us how to
* decompress; this info needs to come totally from the compressed data!
*
****************************************************************************/
void NEAR PASCAL MyDecompress8(
INSTINFO * pinst,
LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
LPBITMAPINFOHEADER lpbiOutput, HPBYTE hpOutput,
DWORD ckid)
{
WORD x,y,xrun ;
WORD wRealLineSize ;
WORD wLinePad ;
ICSTATE icstate ;
WORD wWidth = (WORD)lpbiOutput->biWidth ;
WORD wHeight = (WORD)lpbiOutput->biHeight ;
wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth) ;
wLinePad = (WORD)wWidth-wRealLineSize ;
icstate = *(ICSTATE _huge *)hpInput ;
hpInput += sizeof(ICSTATE) ;
for (y=0; y < wHeight; y++)
{
for (x=0; x<wWidth; )
{
xrun = min(wWidth-x,icstate.wPixelKeepRatio) ;
x += xrun ;
while (xrun--)
*hpOutput++ = *hpInput ;
hpInput++ ;
}
hpOutput += wLinePad ;
}
}
void NEAR PASCAL MyDecompress16(
INSTINFO * pinst,
LPBITMAPINFOHEADER lpbiInput, HPWORD hpInput,
LPBITMAPINFOHEADER lpbiOutput, HPWORD hpOutput,
DWORD ckid)
{
WORD x,y,xrun ;
WORD wRealLineSize ;
WORD wLinePad ;
ICSTATE icstate ;
WORD wWidth = (WORD)lpbiOutput->biWidth ;
WORD wHeight = (WORD)lpbiOutput->biHeight ;
WORD wDropBits ;
WORD wKeepBits ;
WORD r,g,b,color ;
BITBUFFER bb ;
wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*2) ;
wLinePad = (WORD)wWidth*2-wRealLineSize ;
icstate = *(ICSTATE _huge *)hpInput ;
hpInput += sizeof(ICSTATE) ;
wDropBits = icstate.wColorBitsToDrop ;
wKeepBits = 5 - wDropBits ;
InitBitBuffer( &bb, hpInput ) ;
for (y=0; y < wHeight; y++)
{
for (x=0; x<wWidth; )
{
r = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
g = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
b = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
color = (r << 10) | (g << 5) | b ;
xrun = min(wWidth-x,icstate.wPixelKeepRatio) ;
x += xrun ;
while (xrun--)
*hpOutput++ = color ;
}
hpOutput += wLinePad ;
}
}
void NEAR PASCAL MyDecompress24(
INSTINFO * pinst,
LPBITMAPINFOHEADER lpbiInput, HPBYTE hpInput,
LPBITMAPINFOHEADER lpbiOutput, HPBYTE hpOutput,
DWORD ckid)
{
WORD x,y,xrun ;
WORD wRealLineSize ;
WORD wLinePad ;
ICSTATE icstate ;
WORD wWidth = (WORD)lpbiOutput->biWidth ;
WORD wHeight = (WORD)lpbiOutput->biHeight ;
WORD wDropBits ;
WORD wKeepBits ;
WORD r,g,b ;
BITBUFFER bb ;
wRealLineSize = (WORD)ALIGNULONG((DWORD)wWidth*3) ;
wLinePad = (WORD)wWidth*3-wRealLineSize ;
icstate = *(ICSTATE _huge *)hpInput ;
hpInput += sizeof(ICSTATE) ;
wDropBits = icstate.wColorBitsToDrop ;
wKeepBits = 8 - wDropBits ;
InitBitBuffer( &bb, hpInput ) ;
for (y=0; y < wHeight; y++)
{
for (x=0; x<wWidth; )
{
r = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
g = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
b = (WORD)InputBits( &bb, wKeepBits ) << wDropBits ;
xrun = min(wWidth-x,icstate.wPixelKeepRatio) ;
x += xrun ;
while (xrun--)
{
*hpOutput++ = (BYTE)b ;
*hpOutput++ = (BYTE)g ;
*hpOutput++ = (BYTE)r ;
}
}
hpOutput += wLinePad ;
}
}
/*****************************************************************************
*
* Load() is called from the ICM_LOAD message.
*
* Tasks such as allocating global memory that is non-instance specific
* or initializing coprocessor hardware may be performed here.
*
* Our simple case needs none of this.
*
****************************************************************************/
BOOL NEAR PASCAL Load(void)
{
DPF("Load()");
return TRUE;
}
/*****************************************************************************
*
* Free() is called from the ICM_FREE message.
*
* It should totally reverse the effects of Load() in preparation for
* the DRV being removed from memory.
*
****************************************************************************/
void NEAR PASCAL Free()
{
DPF("Free()");
}
/*****************************************************************************
*
* Open() is called from the ICM_OPEN message
*
* This message will be sent for a particular compress/decompress session.
* Our code must verify that we are indeed being called as a video
* compressor and create/initialize a state structure. The ICM will
* give us back the pointer to that structure on every message dealing
* with this session.
*
****************************************************************************/
INSTINFO * NEAR PASCAL Open(ICOPEN FAR * icinfo)
{
INSTINFO * pinst;
DPF("Open('%4.4ls', '%4.4ls')", (LPSTR)&icinfo->fccType, (LPSTR)&icinfo->fccHandler);
//
// refuse to open if we are not being opened as a Video compressor
//
if (icinfo->fccType != ICTYPE_VIDEO)
return NULL;
pinst = (INSTINFO *)LocalAlloc(LPTR, sizeof(INSTINFO));
if (!pinst)
{
icinfo->dwError = ICERR_MEMORY;
return NULL;
}
//
// init structure
//
pinst->fccType = ICTYPE_VIDEO;
pinst->dwFlags = icinfo->dwFlags;
pinst->nCompress = 0;
pinst->nDecompress = 0;
pinst->nDraw = 0;
//
// set the default state.
//
SetState(pinst, NULL, 0);
//
// return success.
//
icinfo->dwError = ICERR_OK;
return pinst;
}
/*****************************************************************************
*
* Close() is called on the ICM_CLOSE message.
*
* This message is the complement to ICM_OPEN and marks the end
* of a compress/decompress session. We kill any in-progress operations
* (although this shouldn't be needed) and free our instance structure.
*
****************************************************************************/
DWORD NEAR PASCAL Close(INSTINFO * pinst)
{
DPF("Close()");
while (pinst->nCompress > 0)
CompressEnd(pinst);
while (pinst->nDecompress > 0)
DecompressEnd(pinst);
while (pinst->nDraw > 0)
DrawEnd(pinst);
LocalFree((HLOCAL)pinst);
return 1;
}
/*****************************************************************************
*
* QueryAbout() and About() handle the ICM_ABOUT message.
*
* QueryAbout() returns TRUE to indicate we support an about box.
* About() displays the box.
*
****************************************************************************/
BOOL NEAR PASCAL QueryAbout(INSTINFO * pinst)
{
DPF("QueryAbout()");
return TRUE;
}
DWORD NEAR PASCAL About(INSTINFO * pinst, HWND hwnd)
{
DPF("About()");
MessageBox(hwnd,szDescription,szName,MB_OK|MB_ICONINFORMATION);
return ICERR_OK;
}
/*****************************************************************************
*
* QueryConfigure() and Configure() implement the ICM_CONFIGURE message.
*
* These functions put up a dialog that allows the user, if he so
* chooses, to modify the configuration portion of our state info.
*
****************************************************************************/
BOOL NEAR PASCAL QueryConfigure(INSTINFO * pinst)
{
DPF("QueryConfigure()");
return TRUE;
}
DWORD NEAR PASCAL Configure(INSTINFO * pinst, HWND hwnd)
{
DPF("Configure()");
return DialogBoxParam(ghModule,"Configure",hwnd,ConfigureDlgProc, (LONG)(WORD)pinst);
}
/*****************************************************************************
*
* GetState() implements the ICM_GETSTATE message.
*
* We copy our configuration information and return how many bytes it took.
*
****************************************************************************/
DWORD NEAR PASCAL GetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
{
DPF("GetState(%08lX, %ld)", pv, dwSize);
if (pv == NULL || dwSize == 0)
return sizeof(ICSTATE);
if (dwSize < sizeof(ICSTATE))
return 0;
*((ICSTATE FAR *)pv) = pinst->CurrentState;
// return number of bytes copied
return sizeof(ICSTATE);
}
/*****************************************************************************
*
* SetState() implements the ICM_SETSTATE message.
*
* The ICM is giving us configuration information saved by GetState()
* earlier.
*
****************************************************************************/
DWORD NEAR PASCAL SetState(INSTINFO * pinst, LPVOID pv, DWORD dwSize)
{
DPF("SetState(%08lX, %ld)", pv, dwSize);
//
// make sure we created this state information.
//
if (pv && ((ICSTATE FAR *)pv)->fccHandler != FOURCC_SAMP)
return 0;
if (pv == NULL)
pinst->CurrentState = DefaultState;
else if (dwSize >= sizeof(ICSTATE))
pinst->CurrentState = *((ICSTATE FAR *)pv);
else
return 0;
// return number of bytes copied
return sizeof(ICSTATE);
}
/*****************************************************************************
*
* GetInfo() implements the ICM_GETINFO message
*
* We just fill in the structure to tell the ICM what we can do. The flags
* (none of which this sample supports) mean the following :
*
* VIDCF_QUALITY - we support the quality variable. This means we look at
* dwQuality in the ICINFO structure when compressing and
* make a concious decision to trade quality for space.
* (higher values of dwQuality mean quality is more
* important). dwQuality is set by the ICM.
*
* VIDCF_TEMPORAL - We do interframe compression. In this algorithm, not
* every frame is a "key frame"; some frames depend on
* other frames to be generated. An example of this might
* be to store frame buffer differences until the
* differences are big enough to no longer make this
* worthwhile, then storing another complete frame and
* starting over. In this case, the complete frames that
* are stored are key frames and should be flagged as
* such.
*
* VIDCF_DRAW - We will draw the decompressed image on our own. This is
* useful if the decompression is assisted by the video
* hardware.
*
****************************************************************************/
DWORD NEAR PASCAL GetInfo(INSTINFO * pinst, ICINFO FAR *icinfo, DWORD dwSize)
{
DPF("GetInfo()");
if (icinfo == NULL)
return sizeof(ICINFO);
if (dwSize < sizeof(ICINFO))
return 0;
icinfo->dwSize = sizeof(ICINFO);
icinfo->fccType = ICTYPE_VIDEO;
icinfo->fccHandler = FOURCC_SAMP;
icinfo->dwFlags = 0;
// VIDCF_QUALITY // supports quality
// VIDCF_TEMPORAL // supports inter-frame
// VIDCF_DRAW // supports drawing
icinfo->dwVersion = VERSION_SAMP;
icinfo->dwVersionICM = ICVERSION;
lstrcpy(icinfo->szDescription, szDescription);
lstrcpy(icinfo->szName, szName);
return sizeof(ICINFO);
}
/*****************************************************************************
*
* CompressQuery() handles the ICM_COMPRESSQUERY message
*
* This message basically asks, "Can you compress this into this?"
*
* We look at the input and output bitmap info headers and determine
* if we can.
*
****************************************************************************/
LRESULT NEAR PASCAL CompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
DPF("CompressQuery()");
//
// determine if the input DIB data is in a format we like.
//
if (lpbiIn == NULL ||
(lpbiIn->biBitCount != 8 && lpbiIn->biBitCount != 16 && lpbiIn->biBitCount != 24) ||
lpbiIn->biCompression != BI_RGB)
{
return ICERR_BADFORMAT;
}
//
// are we being asked to query just the input format?
//
if (lpbiOut == NULL)
return ICERR_OK;
//
// make sure we can handle the format to compress to also.
//
if (lpbiOut->biCompression != BI_SAMP || // must be 'Smp1'
lpbiOut->biBitCount != lpbiIn->biBitCount ||
lpbiOut->biWidth != lpbiIn->biWidth || // must be 1:1 (no stretch)
lpbiOut->biHeight != lpbiIn->biHeight)
{
return ICERR_BADFORMAT;
}
return ICERR_OK;
}
/*****************************************************************************
*
* CompressGetFormat() implements ICM_GETFORMAT
*
* This message asks, "If I gave you this bitmap, how much memory would it
* be compressed?"
*
* If the output bitmap info header is NULL, we just return how big the
* header would be (header + palette, actually)
*
* Otherwise, we fill in the header, most importantly the biSizeImage.
* This field must contain an upper bound on the size of the compressed
* frame. A value that is too high here will result in inefficient
* memory allocation at compression time, but will not be reflected
* to the stored bitmap - the compression algorithm may chop biSizeImage
* down to the actual amount with no ill effects.
*
****************************************************************************/
LRESULT NEAR PASCAL CompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
DWORD dw;
DPF("CompressGetFormat()");
if (dw = CompressQuery(pinst, lpbiIn, NULL))
return dw;
//
// if lpbiOut == NULL then, return the size required to hold a output
// format
//
if (lpbiOut == NULL)
return (int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
hmemcpy(lpbiOut, lpbiIn,
(int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
lpbiOut->biBitCount = lpbiIn->biBitCount;
lpbiOut->biCompression = BI_SAMP;
lpbiOut->biSizeImage = CompressGetSize(pinst, lpbiIn, lpbiOut);
return ICERR_OK;
}
/*****************************************************************************
*
* CompressBegin() implements ICM_COMPRESSBEGIN
*
* We're about to start compressing, initialize coprocessor, etc.
*
****************************************************************************/
LRESULT NEAR PASCAL CompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
DWORD dw;
DPF("CompressBegin()");
if (dw = CompressQuery(pinst, lpbiIn, lpbiOut))
return dw;
if (pinst->nCompress++ > 0)
return ICERR_OK;
//
// initialize for compression, for real....
//
return ICERR_OK;
}
/*****************************************************************************
*
* CompressGetSize() implements ICM_COMPRESS_GET_SIZE
*
* This function returns how much (upper bound) memory a compressed frame
* will take.
*
****************************************************************************/
LRESULT NEAR PASCAL CompressGetSize(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
int dx,dy;
WORD wPixRatio = pinst->CurrentState.wPixelKeepRatio ;
WORD wPixelSize ;
DPF("CompressGetSize()");
dx = (int)lpbiIn->biWidth;
dy = (int)lpbiIn->biHeight;
wPixelSize = (lpbiOut->biBitCount+7)/8 ;
return
sizeof(ICSTATE) +
wPixelSize*(DWORD)dx*dy ;
}
/*****************************************************************************
*
* Compress() implements ICM_COMPRESS
*
* Everything is set up; call the actual compression routine.
*
* Note:
*
* 1) We set the ckid in icinfo to a two-character code indicating how we
* compressed. This code will be returned to us at decompress time to
* allow us to pick a decompression algorithm to match. This is different
* from icinfo->fccHandler, which tells which driver to use!
*
* 2) We set the key-frame flag on every frame since we do no
* temporal (inter-frame) compression.
*
****************************************************************************/
LRESULT NEAR PASCAL Compress(INSTINFO * pinst, ICCOMPRESS FAR *icinfo, DWORD dwSize)
{
DWORD dw;
DPF("Compress()");
//
// check for being called without a BEGIN message
//
// this should never happen, it is ok to fail this.
//
if (pinst->nCompress == 0)
{
if (dw = CompressBegin(pinst, icinfo->lpbiInput, icinfo->lpOutput))
return dw;
}
if (dw = CompressQuery(pinst, icinfo->lpbiInput, icinfo->lpbiOutput))
return dw;
/* do the compression */
switch(icinfo->lpbiInput->biBitCount)
{
case 8 :
MyCompress8(pinst,icinfo->lpbiInput, icinfo->lpInput,
icinfo->lpbiOutput, icinfo->lpOutput);
break ;
case 16 :
MyCompress16(pinst,icinfo->lpbiInput, icinfo->lpInput,
icinfo->lpbiOutput, icinfo->lpOutput);
break ;
case 24 :
MyCompress24(pinst,icinfo->lpbiInput, icinfo->lpInput,
icinfo->lpbiOutput, icinfo->lpOutput);
break ;
}
//
// return the chunk id
//
if (icinfo->lpckid)
*icinfo->lpckid = TWOCC_SAMP;
//
// set the AVI index flags,
//
// make it a keyframe
//
if (icinfo->lpdwFlags)
*icinfo->lpdwFlags = AVIIF_KEYFRAME;
return ICERR_OK;
}
/*****************************************************************************
*
* CompressEnd() is called on ICM_COMPRESS_END
*
* This function is a chance to flush buffers, deinit hardware, etc.
* after compressing a single frame.
*
****************************************************************************/
LRESULT NEAR PASCAL CompressEnd(INSTINFO * pinst)
{
DPF("CompressEnd()");
if (pinst->nCompress == 0)
return ICERR_ERROR;
if (--pinst->nCompress > 0)
return ICERR_OK;
/* *** your code here *** */
return ICERR_OK;
}
/*****************************************************************************
*
* DecompressQuery() implements ICM_DECOMPRESS_QUERY
*
* See CompressQuery()
*
****************************************************************************/
LRESULT NEAR PASCAL DecompressQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
DPF("DecompressQuery()");
//
// determine if the input DIB data is in a format we like.
//
if (lpbiIn == NULL ||
(lpbiIn->biBitCount != 8 && lpbiIn->biBitCount != 16 && lpbiIn->biBitCount != 24) ||
lpbiIn->biCompression != BI_SAMP)
{
return ICERR_BADFORMAT;
}
//
// are we being asked to query just the input format?
//
if (lpbiOut == NULL)
return ICERR_OK;
//
// make sure we can handle the format to compress too.
//
if (lpbiOut->biCompression != BI_RGB || // must be full dib
lpbiOut->biBitCount != lpbiIn->biBitCount ||
lpbiOut->biWidth != lpbiIn->biWidth || // must be 1:1 (no stretch)
lpbiOut->biHeight != lpbiIn->biHeight)
{
return ICERR_BADFORMAT;
}
return ICERR_OK;
}
/*****************************************************************************
*
* DecompressGetFormat() implements ICM_DECOMPRESS_GET_FORMAT
*
* See CompressGetFormat()
*
****************************************************************************/
LRESULT NEAR PASCAL DecompressGetFormat(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
DWORD dw;
int dx,dy;
WORD wBytesPerPixel ;
DPF("DecompressGetFormat()");
if (dw = DecompressQuery(pinst, lpbiIn, NULL))
return dw;
//
// if lpbiOut == NULL then, return the size required to hold an output
// format
//
if (lpbiOut == NULL)
return (int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD);
hmemcpy(lpbiOut, lpbiIn,
(int)lpbiIn->biSize + (int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
dx = (int)lpbiIn->biWidth;
dy = (int)lpbiIn->biHeight;
wBytesPerPixel = (lpbiIn->biBitCount+7)/8 ;
lpbiOut->biBitCount = lpbiIn->biBitCount ;
lpbiOut->biCompression = BI_RGB;
lpbiOut->biSizeImage = wBytesPerPixel*(DWORD)dy*(DWORD)((dx+3)&~3);
return ICERR_OK;
}
/*****************************************************************************
*
* DecompressGetPalette() implements ICM_GET_PALETTE
*
* This function has no Compress...() equivalent
*
* It is used to pull the palette from a frame in order to possibly do
* a palette change.
*
****************************************************************************/
LRESULT NEAR PASCAL DecompressGetPalette(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
DWORD dw;
DPF("DecompressGetPalette()");
if (dw = DecompressQuery(pinst, lpbiIn, lpbiOut))
return dw;
if (lpbiOut->biBitCount != 8)
return ICERR_BADFORMAT;
//
// if you decompress full-color to 8 bit you need to put the "dither"
// palette in lpbiOut
//
if (lpbiIn->biBitCount != 8)
return ICERR_BADFORMAT;
if (lpbiIn->biClrUsed == 0)
lpbiIn->biClrUsed = 256;
//
// return the 8bit palette used for decompression.
//
hmemcpy(
(LPBYTE)lpbiOut + (int)lpbiOut->biSize,
(LPBYTE)lpbiIn + (int)lpbiIn->biSize,
(int)lpbiIn->biClrUsed * sizeof(RGBQUAD));
lpbiOut->biClrUsed = lpbiIn->biClrUsed;
return ICERR_OK;
}
/*****************************************************************************
*
* DecompressBegin() implements ICM_DECOMPRESS_BEGIN
*
* See CompressBegin()
*
****************************************************************************/
LRESULT NEAR PASCAL DecompressBegin(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiIn, LPBITMAPINFOHEADER lpbiOut)
{
DWORD dw;
DPF("DecompressBegin()");
if (dw = DecompressQuery(pinst, lpbiIn, lpbiOut))
return dw;
if (pinst->nDecompress++ > 0)
return ICERR_OK;
//
// start of decompress
//
return ICERR_OK;
}
/*****************************************************************************
*
* Decompress() implements ICM_DECOMPRESS
*
* See DecompressBegin()
*
****************************************************************************/
LRESULT NEAR PASCAL Decompress(INSTINFO * pinst, ICDECOMPRESS FAR *icinfo, DWORD dwSize)
{
DWORD ckid;
DWORD dw;
DPF("Decompress()");
//
// check for being called without a BEGIN message
//
// this should never happen, it is ok to fail this.
//
if (pinst->nDecompress == 0)
{
if (dw = DecompressBegin(pinst, icinfo->lpbiInput, icinfo->lpOutput))
return dw;
}
//
// because 'SAMP' frames are key frames we dont need to do any thing if
// behind.
//
if (icinfo->dwFlags & ICDECOMPRESS_HURRYUP)
return ICERR_OK;
//
// get the chunk id, we realy dont care much about it because we
// only have one type of data
//
ckid = icinfo->ckid;
/* do the decompression */
switch(icinfo->lpbiInput->biBitCount)
{
case 8 :
MyDecompress8(pinst,icinfo->lpbiInput, icinfo->lpInput,
icinfo->lpbiOutput, icinfo->lpOutput, ckid);
break ;
case 16 :
MyDecompress16(pinst,icinfo->lpbiInput, icinfo->lpInput,
icinfo->lpbiOutput, icinfo->lpOutput, ckid);
break ;
case 24 :
MyDecompress24(pinst,icinfo->lpbiInput, icinfo->lpInput,
icinfo->lpbiOutput, icinfo->lpOutput, ckid);
break ;
}
return ICERR_OK;
}
/*****************************************************************************
*
* DecompressEnd() implements ICM_DECOMPRESS_END
*
* See CompressEnd()
*
****************************************************************************/
LRESULT NEAR PASCAL DecompressEnd(INSTINFO * pinst)
{
DPF("DecompressEnd()");
if (pinst->nDecompress == 0)
return ICERR_ERROR;
if (--pinst->nDecompress > 0)
return ICERR_OK;
//
// end of decompress.
//
return ICERR_OK;
}
/*****************************************************************************
*
* DrawQuery() implements ICM_DRAW_QUERY
*
****************************************************************************/
BOOL NEAR PASCAL DrawQuery(INSTINFO * pinst, LPBITMAPINFOHEADER lpbiInput)
{
return FALSE;
}
/*****************************************************************************
*
* DrawBegin() implements ICM_DRAW_BEGIN
*
* This is just like DecompressBegin() except that we also must prepare to
* actually draw the bitmap on the screen. ICDRAWBEGIN provides info specific
* to this task.
*
****************************************************************************/
LRESULT NEAR PASCAL DrawBegin(INSTINFO * pinst,ICDRAWBEGIN FAR *icinfo, DWORD dwSize)
{
DPF("DrawBegin()");
if (1) // we dont draw!
return ICERR_UNSUPPORTED;
if (pinst->nDraw++ > 0)
return ICERR_OK;
//
// but if we did draw we would get ready to draw here
//
return ICERR_OK;
}
/*****************************************************************************
*
* Draw implements ICM_DRAW
*
* Decompress and draw
*
****************************************************************************/
LRESULT NEAR PASCAL Draw(INSTINFO * pinst, ICDRAW FAR *icinfo, DWORD dwSize)
{
DPF("Draw()");
if (pinst->nDraw == 0)
return ICERR_ERROR;
return ICERR_UNSUPPORTED;
}
/*****************************************************************************
*
* DrawEnd() implements ICM_DRAW_END
*
* See DecompressEnd()
*
****************************************************************************/
LRESULT NEAR PASCAL DrawEnd(INSTINFO * pinst)
{
DPF("DrawEnd()");
if (1) // we dont draw!
return ICERR_UNSUPPORTED;
if (pinst->nDraw == 0)
return ICERR_ERROR;
if (--pinst->nDraw > 0)
return ICERR_OK;
//
// but if we did we would clean up here
//
return ICERR_OK;
}
/*****************************************************************************
*
* ConfigureDlgProc() is called by Configure
*
* This is a standard dialog proc which allows the user to
* pick config options for the driver.
*
****************************************************************************/
BOOL FAR PASCAL _loadds ConfigureDlgProc(HWND hdlg, short msg, WORD wParam, LONG lParam)
{
int id;
static int s1;
static int s2;
HWND hsb;
char ach[10];
static INSTINFO *pinst;
#define SCROLL_MIN 1
#define SCROLL_MAX 16
#define SCROLL2_MIN 0
#define SCROLL2_MAX 4
switch (msg)
{
case WM_COMMAND:
switch (wParam)
{
case IDOK:
hsb = GetDlgItem(hdlg,ID_SCROLL);
pinst->CurrentState.wPixelKeepRatio = s1 ;
hsb = GetDlgItem(hdlg,ID_SCROLL2);
pinst->CurrentState.wColorBitsToDrop = s2 ;
EndDialog(hdlg,TRUE);
break;
case IDCANCEL:
EndDialog(hdlg,FALSE);
break;
}
break;
case WM_HSCROLL:
hsb = (HWND)HIWORD(lParam);
id = GetWindowWord(hsb,GWW_ID);
switch( id )
{
case ID_SCROLL:
s1 = GetScrollPos(hsb,SB_CTL);
switch (wParam)
{
case SB_LINEDOWN: s1 += 1; break;
case SB_LINEUP: s1 -= 1; break;
case SB_PAGEDOWN: s1 += 4; break;
case SB_PAGEUP: s1 -= 4; break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION: s1 = (int)LOWORD(lParam); break;
default: return TRUE;
}
s1 = max(SCROLL_MIN,min(SCROLL_MAX,s1));
SetScrollPos(hsb,SB_CTL,s1,TRUE);
wsprintf(ach, "%02d", s1);
SetDlgItemText(hdlg,ID_TEXT,ach);
return TRUE;
case ID_SCROLL2:
s2 = GetScrollPos(hsb,SB_CTL);
switch (wParam)
{
case SB_LINEDOWN: s2 += 1; break;
case SB_LINEUP: s2 -= 1; break;
case SB_PAGEDOWN: s2 += 4; break;
case SB_PAGEUP: s2 -= 4; break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION: s2 = (int)LOWORD(lParam); break;
default: return TRUE;
}
s2 = max(SCROLL2_MIN,min(SCROLL2_MAX,s2));
SetScrollPos(hsb,SB_CTL,s2,TRUE);
wsprintf(ach, "%02d", s2);
SetDlgItemText(hdlg,ID_TEXT2,ach);
return TRUE;
}
return TRUE ;
case WM_INITDIALOG:
pinst = (INSTINFO *)lParam;
hsb = GetDlgItem(hdlg,ID_SCROLL);
s1 = pinst->CurrentState.wPixelKeepRatio;
SetScrollRange(hsb,SB_CTL,SCROLL_MIN, SCROLL_MAX, TRUE);
SetScrollPos(hsb,SB_CTL,s1,TRUE);
wsprintf(ach, "%02d", s1);
SetDlgItemText(hdlg,ID_TEXT,ach);
hsb = GetDlgItem(hdlg,ID_SCROLL2);
s2 = pinst->CurrentState.wColorBitsToDrop;
SetScrollRange(hsb,SB_CTL,SCROLL2_MIN, SCROLL2_MAX, TRUE);
SetScrollPos(hsb,SB_CTL,s2,TRUE);
wsprintf(ach, "%02d", s2);
SetDlgItemText(hdlg,ID_TEXT2,ach);
return TRUE;
}
return FALSE;
}
/*****************************************************************************
*
* dprintf() is called by the DPF macro if DEBUG is defined at compile time.
*
* The messages will be send to COM1: like any debug message. To
* enable debug output, add the following to WIN.INI :
*
* [debug]
* ICSAMPLE=1
*
****************************************************************************/
#ifdef DEBUG
void FAR cdecl dprintf(LPSTR szFormat, ...)
{
char ach[128];
static BOOL fDebug = -1;
if (fDebug == -1)
fDebug = GetProfileInt("Debug", MODNAME, FALSE);
if (!fDebug)
return;
lstrcpy(ach, MODNAME ": ");
wvsprintf(ach+lstrlen(ach),szFormat,(LPSTR)(&szFormat+1));
lstrcat(ach, "\r\n");
OutputDebugString(ach);
}
#endif